home *** CD-ROM | disk | FTP | other *** search
- /* Internet Control Message Protocol */
-
- #include "machdep.h"
- #include "internet.h"
- #include "timer.h"
- #include "ip.h"
- #include "icmp.h"
- #include "mbuf.h"
-
- int (*echo_proc)(); /* Handler for Echo Reply messages */
-
- struct icmp_errors icmp_errors;
- struct icmp_stats icmp_stats;
-
- /* Process an incoming ICMP packet */
- void
- icmp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
- struct mbuf *bp; /* Pointer to ICMP message */
- char protocol; /* Should always be ICMP_PTCL */
- int32 source; /* Sender of ICMP message */
- int32 dest; /* Us */
- char tos; /* Type of Service */
- int16 length; /* Length of ICMP message */
- char rxbroadcast;
- {
-
- struct icmp *icmph; /* Pointer to ICMP message */
- struct ip_header *iph; /* Offending datagram header */
- int16 type; /* Type of ICMP message */
- int16 ip_len;
-
- if(rxbroadcast){
- /* Broadcast ICMP packets are to be IGNORED !! */
- icmp_errors.bdcsts++;
- free_p(bp);
- return;
- }
- if(cksum(NULLHEADER,bp,length) != 0){
- /* Bad ICMP checksum; discard */
- icmp_errors.checksum++;
- free_p(bp);
- return;
- }
- /* If the message is fragmented, copy to a contiguous mbuf */
- if(bp->next != NULLBUF){
- struct mbuf *nbp;
-
- nbp = copy_p(bp,length);
- free_p(bp);
- if(nbp == NULLBUF){
- icmp_errors.nospace++;
- return;
- }
- bp = nbp;
- }
- icmph = (struct icmp *)bp->data;
-
- /* Process the message. Some messages are passed up to the protocol
- * module for handling, others are handled here.
- */
- type = icmph->type & 0xff;
- if(type < ICMP_TYPES)
- icmp_stats.input[type]++;
-
- switch(type){
- case TIME_EXCEED: /* Time-to-live Exceeded */
- case DEST_UNREACH: /* Destination Unreachable */
- case QUENCH: /* Source Quench */
- iph = (struct ip_header *)(icmph + 1);
- ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
-
- switch(iph->protocol){
- case TCP_PTCL:
- tcp_icmp(ntohl(iph->source),ntohl(iph->dest),
- icmph->type,icmph->code,(char *)iph + ip_len);
- break;
- }
- break;
- case ECHO: /* Echo Request */
- /* Change type to ECHO_REPLY, recompute checksum,
- * and return datagram.
- */
- icmph->type = ECHO_REPLY;
- icmph->checksum = 0;
- icmph->checksum = cksum(NULLHEADER,bp,length);
- icmp_stats.output[ECHO_REPLY]++;
- ip_send(dest,source,ICMP_PTCL,tos,0,bp,length,0,0);
- return;
- case REDIRECT: /* Redirect */
- case PARAM_PROB: /* Parameter Problem */
- break;
- case ECHO_REPLY: /* Echo Reply */
- if(echo_proc){
- (*echo_proc)(ntohl(iph->source),ntohl(iph->dest),
- icmph->type,icmph->code,(char *)iph + ip_len);
- }
- break;
- case TIMESTAMP: /* Timestamp */
- case TIME_REPLY: /* Timestamp Reply */
- case INFO_RQST: /* Information Request */
- case INFO_REPLY: /* Information Reply */
- break;
- }
- free_p(bp);
- }
- /* Return an ICMP response to the sender of a datagram */
- icmp_output(bp,type,code,args)
- struct mbuf *bp; /* Pointer to offending IP header + data */
- char type,code; /* Codes to send */
- union icmp_args *args;
- {
- struct ip_header *iph; /* Offending IP header */
- int16 ip_len; /* Length of offending IP header */
-
- struct mbuf *reply; /* Buffer with ICMP reply */
- struct icmp *icmph; /* ICMP protocol header */
- struct mbuf *data; /* Returned portion of offending packet */
- int16 dlen; /* Length of data portion of offending pkt */
- int16 length; /* Total length of reply */
- extern int32 ip_addr; /* Our IP address */
-
- if(type < ICMP_TYPES)
- icmp_stats.output[type]++;
-
- iph = (struct ip_header *)bp->data;
-
- if(iph->protocol == ICMP_PTCL){
- icmp_errors.noloop++;
- return; /* Never send an ICMP message about another ICMP message */
- }
- /* Compute amount of original datagram to return.
- * We return the original IP header, and up to 8 bytes past that.
- */
- ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
- dlen = ntohs(iph->length);
- if(dlen > ip_len + 8)
- dlen = ip_len + 8;
- length = sizeof(struct icmp) + dlen;
-
- /* Allocate ICMP header and fill in */
- if((reply = alloc_mbuf(sizeof(struct icmp))) == NULLBUF){
- /* No space; don't bother */
- icmp_errors.nospace++;
- return;
- }
- reply->cnt = sizeof(struct icmp);
- icmph = (struct icmp *)reply->data;
- icmph->type = type;
- icmph->code = code;
- if(args != (union icmp_args *)NULL)
- icmph->args.unused = args->unused; /* copies whole union */
- else
- icmph->args.unused = 0;
-
- /* Link in a copy of the beginning of the original datagram */
- data = copy_p(bp,dlen);
- reply->next = data; /* Could be NULL if copy fails */
-
- /* Compute ICMP checksum and send */
- icmph->checksum = 0;
- icmph->checksum = cksum(NULLHEADER,reply,length);
-
- ip_send(ip_addr,ntohl(iph->source),ICMP_PTCL,iph->tos,0,reply,length,0,0);
- }
- #ifdef TRACE
- /* ICMP message types */
- char *icmptypes[] = {
- "Echo Reply",
- NULLCHAR,
- NULLCHAR,
- "Unreachable",
- "Source Quench",
- "Redirect",
- NULLCHAR,
- NULLCHAR,
- "Echo Request",
- NULLCHAR,
- NULLCHAR,
- "Time Exceeded",
- "Parameter Problem",
- "Timestamp",
- "Timestamp Reply",
- "Information Request",
- "Information Reply"
- };
-
- /* ICMP unreachable messages */
- char *unreach[] = {
- "Network",
- "Host",
- "Protocol",
- "Port",
- "Fragmentation",
- "Source route"
- };
- /* ICMP Time exceeded messages */
- char *exceed[] = {
- "Time-to-live",
- "Fragment reassembly"
- };
-
- /* ICMP redirect messages */
- char *redirect[] = {
- "Network",
- "Host",
- "TOS & Network",
- "TOS & Host"
- };
-
- int
- doicmpstat(argc,argv)
- int argc;
- char *argv[];
- {
- extern struct icmp_errors icmp_errors;
- extern struct icmp_stats icmp_stats;
- register int i;
-
- printf("chksum err %u no space %u icmp %u bdcsts %u\r\n",
- icmp_errors.checksum,icmp_errors.nospace,icmp_errors.noloop,
- icmp_errors.bdcsts);
- printf("type rcvd sent\r\n");
- for(i=0;i<ICMP_TYPES;i++){
- if(icmp_stats.input[i] == 0 && icmp_stats.output[i] == 0)
- continue;
- printf("%-6u%-6u%-6u",i,icmp_stats.input[i],
- icmp_stats.output[i]);
- if(icmptypes[i] != NULLCHAR)
- printf(" %s",icmptypes[i]);
- printf("\r\n");
- }
- return 0;
- }
- /* Dump an ICMP header */
- void
- icmp_dump(bp,source,dest,check)
- struct mbuf *bp;
- int32 source,dest;
- int check; /* If 0, bypass checksum verify */
- {
- register struct icmp *icmp;
- char *codemsg;
- struct mbuf *ibp;
- int i;
- char tmpbuf;
-
- if(bp == NULLBUF)
- return;
- /* If packet isn't in a single buffer, make a temporary copy and
- * note the fact so we free it later
- */
- if(bp->next != NULLBUF){
- bp = copy_p(bp,len_mbuf(bp));
- tmpbuf = 1;
- } else
- tmpbuf = 0;
-
- codemsg = NULLCHAR;
- icmp = (struct icmp *)bp->data;
- if(icmp->type <= 16 && icmptypes[icmp->type] != NULLCHAR)
- printf("ICMP: %s",icmptypes[icmp->type]);
- else
- printf("ICMP: type %u",icmp->type);
-
- switch(icmp->type){
- case DEST_UNREACH:
- if(icmp->code <= 5)
- codemsg = unreach[icmp->code];
- break;
- case REDIRECT:
- if(icmp->code <= 3)
- codemsg = redirect[icmp->code];
- break;
- case TIME_EXCEED:
- if(icmp->code <= 1)
- codemsg = exceed[icmp->code];
- break;
- }
- if(codemsg != NULLCHAR)
- printf(" %s",codemsg);
- else
- printf(" code %u",icmp->code);
-
- /* Special case for parameter problem message */
- if(icmp->type == PARAM_PROB)
- printf(" pointer = 0x%x",icmp->args.pointer);
-
- if(check){
- /* Verify checksum */
- if((i = cksum(NULLHEADER,bp,len_mbuf(bp))) != 0)
- printf(" CHECKSUM ERROR (%u)",i);
- }
- printf("\r\n");
- /* Dump the offending IP header, if any */
- switch(icmp->type){
- case DEST_UNREACH:
- case TIME_EXCEED:
- case PARAM_PROB:
- case QUENCH:
- case REDIRECT:
- printf("Returned ");
- dup_p(&ibp,bp,sizeof(struct icmp),
- len_mbuf(bp) - sizeof(struct icmp));
- ip_dump(ibp);
- free_p(ibp);
- }
- if(tmpbuf)
- free_p(bp);
- }
- #endif
-